/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "dac.h"
#include "dma.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "fsmc.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "lcd_3.5tft.h"
#include "arm_math.h"
#include "arm_const_structs.h"
#include "dsp/window_functions.h"
#include <stdio.h>
#include "AD1.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
void fftCalculate(void);
void Draw_Border();
void Draw_Waveform_Optimized();
void Draw_Spectrum_Optimized();
void generateSineWave(uint16_t *sineWaveArray, uint16_t numPoints);
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define LCD_WIDTH  480      // 你的 LCD 宽度
#define LCD_HEIGHT 320      // 你的 LCD 高度
#define ADC_MAX    4095     // 你的 ADC 最大值（12-bit ADC = 4095）
#define WAVEFORM_THICKNESS 2 // 单位：像素
#define  FFT_LENGTH		   4096
#define  ADC1_DMA_Size	   4096

#define DISPLAY_X_START 0                   // 起始X坐标
#define DISPLAY_X_END   (LCD_WIDTH / 2 - 1) // 结束X坐标（宽度减半）
#define DISPLAY_Y_START 0                   // 起始Y坐标
#define DISPLAY_Y_END   (LCD_HEIGHT / 2 - 1)// 结束Y坐标（高度减半）
#define DISPLAY_WIDTH   (LCD_WIDTH / 2)     // 显示区域宽度
#define DISPLAY_HEIGHT  (LCD_HEIGHT / 2)    // 显示区域高度

#define DISPLAY_X_START 0                   // 起始X坐标
#define DISPLAY_X_END   (LCD_WIDTH / 2 - 1) // 结束X坐标（宽度减半）
#define DISPLAY_Y_START 0                   // 起始Y坐标
#define DISPLAY_Y_END   (LCD_HEIGHT / 2 - 1)// 结束Y坐标（高度减半）
#define DISPLAY_WIDTH   (LCD_WIDTH / 2)     // 显示区域宽度
#define DISPLAY_HEIGHT  (LCD_HEIGHT / 2)    // 显示区域高度
// 时间栅格控制参数
float time_scale = 1.0f;      // 时间缩放系数 (1.0=原始比例)
int time_offset = 0;          // 时间偏移量（像素）
#define MAX_OFFSET 500        // 最大偏移量
#define MIN_SCALE 0.01f        // 最小缩放系数
#define MAX_SCALE 20.0f        // 最大缩放系数
double SCALE_STEP=0.01;       // 缩放步长
#define OFFSET_STEP 10        // 偏移步长
#define HISTORY_SIZE (ADC1_DMA_Size * 2)  // 双倍历史缓冲区
uint16_t ADC_History[HISTORY_SIZE];      // 环形缓冲区
int history_index = 0;                   // 当前写入位置
int last_x = -1, last_y = -1;            // 上一次绘制坐标

int  SAM_FRE  = 1000000 ;//采样率
float    FFT_INPUT[FFT_LENGTH*2];
float    FFT_OUTPUT[FFT_LENGTH];

uint16_t ADC1_ConvertedValue[ ADC1_DMA_Size ];
uint32_t ADC_Over=0;
uint16_t SINLUT[100];//DAC测试
uint32_t index_;// 存放 FFT 输出中最大值的索引
float32_t frequency ;// 用于存放计算结果的频率变量
float32_t Hanning_window[FFT_LENGTH];
double Freq_Zl=1000;
/* USER CODE BEGIN PTD */
void fftCalculate(void);
void Draw_Border();
void Draw_Waveform_Optimized();
void Draw_Spectrum_Optimized();
void generateSineWave(uint16_t *sineWaveArray, uint16_t numPoints);
/* USER CODE END PTD */


/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_FSMC_Init();
  MX_USART1_UART_Init();
  MX_ADC1_Init();
  MX_DAC_Init();
  MX_TIM6_Init();
  MX_TIM3_Init();
  MX_TIM4_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_Base_Start_IT(&htim4);//开启定时器1
  generateSineWave(SINLUT,100);//计算正弦波点数
  LCD_Init();
  HAL_ADC_Start(&hadc1);
  HAL_TIM_Base_Start(&htim3);
  HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC1_ConvertedValue,ADC1_DMA_Size);//ADC DMA搬运
  HAL_TIM_Base_Start(&htim6);
  HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)SINLUT,  100, DAC_ALIGN_12B_R);//DAC DMA搬运

    LCD_DisplayMode(Mode_H);		// 设置显示方向
    LCD_SetBackColor(LCD_BLACK); //设置背景色
    LCD_Clear(); //清屏，刷背景色
    Draw_Border();
    AD9851_Init(ad9851_serial,1);
    HAL_TIM_Base_Start_IT(&htim4);//开启定时器
    //AD9851_Setfq(1000);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

    HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC1_ConvertedValue,ADC1_DMA_Size);//ADC DMA搬运
    while(ADC_Over==1) {
        for (int j = 0; j < FFT_LENGTH; j++)//采样数据转换
        {
            FFT_INPUT[j * 2] = (ADC1_ConvertedValue[j]) * 3.3f / 4095.0f;//12位采样数字值对应为0-3.3伏
            FFT_INPUT[j * 2 + 1] = 0;//交替插零，添加数据的虚部
        }
        fftCalculate();

        LCD_SetAsciiFont(&ASCII_Font32);
        LCD_SetColor(LCD_YELLOW);
        LCD_DisplayString(0,280,"Fre:");
        LCD_DisplayNumber(80, 280, frequency, 9,2);
        LCD_DisplayString(0,240,"Step:");
        LCD_DisplayNumber(80, 240, SCALE_STEP, 5,2);
        LCD_DisplayString(0,200,"Ts:");
        LCD_DisplayNumber(80, 200, time_scale, 5,2);
        LCD_ShowNumMode(Fill_Zero);
        Draw_Spectrum_Optimized();//频谱绘制
        Draw_Waveform_Optimized();//波形绘制
        /**
        char buffer[32];  // 存储格式化后的字符串
        for (int a=0; a < ADC1_DMA_Size; a++)
        {
            int len = sprintf(buffer, "ADC[%d]=%d\r\n", a, ADC1_ConvertedValue[a]);
            HAL_UART_Transmit(&huart1, (uint8_t *) buffer, len, HAL_MAX_DELAY);
            HAL_Delay(1);
         }
        HAL_Delay(2000);
         **/
        ADC_Over = 0;
    }
    HAL_Delay(1); // 控制刷新率
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */
void Draw_Waveform_Optimized() {
    // 1. 更新历史缓冲区（环形缓冲）
    for(int i=0; i<ADC1_DMA_Size; i++) {
        ADC_History[history_index] = ADC1_ConvertedValue[i];
        history_index = (history_index + 1) % HISTORY_SIZE;
    }

    // 2. 清除整个显示区域（简单实现，可优化为局部刷新）
    LCD_SetColor(LCD_BLACK);
    LCD_FillRect(DISPLAY_X_START, DISPLAY_Y_START, DISPLAY_WIDTH, DISPLAY_HEIGHT);

    // 3. 绘制新波形（使用画线函数连接采样点）
    LCD_SetColor(LCD_GREEN);
    float samples_per_pixel = (ADC1_DMA_Size * time_scale) / DISPLAY_WIDTH;

    last_x = -1; // 重置上一次坐标
    for(int x=0; x<DISPLAY_WIDTH; x++) {
        // 计算数据位置（考虑缩放和滚动）
        float sample_pos = history_index - (DISPLAY_WIDTH - x) * samples_per_pixel;
        while(sample_pos < 0) sample_pos += HISTORY_SIZE;

        // 获取当前点Y坐标（中心位置）
        int pos = (int)sample_pos % HISTORY_SIZE;
        int current_y = DISPLAY_HEIGHT - 1 - (ADC_History[pos] * (DISPLAY_HEIGHT - 1) / ADC_MAX);

        // 绘制波形
        if(last_x >= 0) {
            // 使用画线函数连接当前点和上一个点
            LCD_DrawLine(last_x, last_y, x, current_y);

            // 绘制波形厚度（垂直线段）
            if(WAVEFORM_THICKNESS > 1) {
                int half_thick = WAVEFORM_THICKNESS / 2;
                int y1 = current_y - half_thick;
                int y2 = current_y + half_thick;
                y1 = (y1 < 0) ? 0 : y1;
                y2 = (y2 >= DISPLAY_HEIGHT) ? DISPLAY_HEIGHT-1 : y2;
                LCD_DrawLine(x, y1, x, y2);
            }
        }

        last_x = x;
        last_y = current_y;
    }
}
void generateSineWave(uint16_t *sineWaveArray, uint16_t numPoints) {
    // 计算每个点的角度增量
    float angleStep = 2 * M_PI / numPoints;  // 2π是一个周期
    for (uint16_t i = 0; i < numPoints; i++) // 填充数组
    {
        float angle = i * angleStep;// 计算角度
        float sineValue = sin(angle);// 计算正弦值
        sineWaveArray[i] = (uint16_t)((sineValue + 1.0) * 1000 + 1000);
    }
}
void Draw_Border() {
    LCD_SetColor(LCD_GREEN);
    // 右边框
    LCD_DrawLine(DISPLAY_X_END+1, DISPLAY_Y_START, DISPLAY_X_END+1,DISPLAY_Y_END);
    // 下边框
    LCD_DrawLine(DISPLAY_X_END, DISPLAY_Y_END+1, DISPLAY_X_START,DISPLAY_Y_END+1);

}
void fftCalculate(void)// FFT 计算函数
{
    arm_cfft_f32(&arm_cfft_sR_f32_len4096, FFT_INPUT, 0, 1);
    arm_cmplx_mag_f32(FFT_INPUT, FFT_OUTPUT, FFT_LENGTH);
    index_ = 0;// 查找 FFT 输出中的最大值
    float32_t maxValue = FFT_OUTPUT[2];
    uint32_t search_len = FFT_LENGTH / 2; // 只搜索前一半有效频谱
    // 遍历查找最大值
    for (uint32_t i = 2   ; i < search_len; i++) {
        if (FFT_OUTPUT[i] > maxValue) {
            maxValue = FFT_OUTPUT[i];
            index_ = i;
        }
    }
//    arm_max_f32(&FFT_OUTPUT[1], FFT_LENGTH, &maxValue, &index_); // 使用 arm_max_f32 函数快速找到 FFT 输出中的最大值及其索引
    frequency = (float32_t)index_ * (float32_t)SAM_FRE / (float32_t)FFT_LENGTH;// 根据最大值的索引计算信号的频率
}


#define FFT_DISPLAY_X_START   (LCD_WIDTH / 2)  // 频谱显示在右半屏
#define FFT_DISPLAY_X_END     (LCD_WIDTH - 1)
#define FFT_DISPLAY_WIDTH     (LCD_WIDTH / 2)
#define FFT_DISPLAY_HEIGHT    (LCD_HEIGHT / 2)
#define FFT_BAR_WIDTH         2                 // 每个频谱条的宽度（像素）
#define FFT_MAX_DB            60.0f            // 最大dB值（动态范围）

void Draw_Spectrum_Optimized() {
    static int prevBarHeight[FFT_DISPLAY_WIDTH / FFT_BAR_WIDTH] = {0};

    // 1. 擦除上一帧频谱（仅擦除右半屏）
    LCD_SetColor(LCD_BLACK);
    for (int bar = 0; bar < (FFT_DISPLAY_WIDTH / FFT_BAR_WIDTH); bar++) {
        int xStart = FFT_DISPLAY_X_START + bar * FFT_BAR_WIDTH;
        for (int y = 0; y < prevBarHeight[bar]; y++) {
            for (int x = xStart; x < xStart + FFT_BAR_WIDTH; x++) {
                LCD_DrawPoint(x, FFT_DISPLAY_HEIGHT - 1 - y);
            }
        }
    }

    // 2. 计算频谱幅度并绘制新帧
    LCD_SetColor(LCD_BLUE);
    for (int bar = 0; bar < (FFT_DISPLAY_WIDTH / FFT_BAR_WIDTH); bar++) {
        // 取FFT结果的频段（忽略对称部分）
        int fftIndex = 1 + (bar * (FFT_LENGTH / 2 - 1)) / (FFT_DISPLAY_WIDTH / FFT_BAR_WIDTH);//忽略直流分量
        //int fftIndex = (bar * (FFT_LENGTH / 2)) / (FFT_DISPLAY_WIDTH / FFT_BAR_WIDTH);
        float magnitude = FFT_OUTPUT[fftIndex];  // 直接取值
        // 转换为dB值（可选，避免log(0)）
        float db = 10.0f * log10f(magnitude + 1e-6f);
        db = (db < 0) ? 0 : db;  // 限制最小值

        // 归一化到显示高度
        int barHeight = (int)((db / FFT_MAX_DB) * FFT_DISPLAY_HEIGHT);
        barHeight = (barHeight > FFT_DISPLAY_HEIGHT) ? FFT_DISPLAY_HEIGHT : barHeight;

        // 保存当前高度（用于下一帧擦除）
        prevBarHeight[bar] = barHeight;

        // 绘制频谱条（从下向上）
        int xStart = FFT_DISPLAY_X_START + bar * FFT_BAR_WIDTH;
        for (int y = 0; y < barHeight; y++) {
            for (int x = xStart; x < xStart + FFT_BAR_WIDTH; x++) {
                LCD_DrawPoint(x, FFT_DISPLAY_HEIGHT - 1 - y);
            }
        }
    }
}
//void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
//{
//    if(GPIO_Pin==Key1_Pin)
//    {
//        time_scale += SCALE_STEP;
//        if (time_scale > MAX_SCALE) time_scale = MAX_SCALE;
//    }
//    if(GPIO_Pin==Key2_Pin)
//    {
//        time_scale -= SCALE_STEP;
//        if (time_scale < MIN_SCALE) time_scale = MIN_SCALE;
//    }
//    if(GPIO_Pin==Key3_Pin)
//    {
//        static uint8_t click_count = 0;
//        click_count++;
//        if(click_count > 3) click_count = 0;
//        // 直接轮换赋值
//        switch(click_count)
//        {
//            case 0: SCALE_STEP = 0.01f; break;
//            case 1: SCALE_STEP = 0.1f;  break;
//            case 2: SCALE_STEP = 1.0f;  break;
//        }
//    }
//    if(GPIO_Pin==Key4_Pin)
//    {
//        //Fre=Fre-1000.0;
//    }
//    if(GPIO_Pin==Key5_Pin)
//    {
//
//    }
//}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim == (&htim4))
    {
        Freq_Zl=Freq_Zl+200.0;
        AD9851_Setfq(Freq_Zl);
        if (Freq_Zl==50000)Freq_Zl=1000;
    }
}
/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
